package com.cup.plat.config;

import java.io.IOException;
import java.sql.SQLException;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.cup.common.response.ResponseCode;
import com.cup.common.response.ResponseData;

@ControllerAdvice
public class WebExceptionHandler {
	
	private Logger logger = LoggerFactory.getLogger(WebExceptionHandler.class);
	
	private static final String RUNTIME_EXP_MSG = "system exception!";
	
	private static final String SQL_EXP_MSG = "sql exception!";
	
	private static final String IO_EXP_MSG = "io exception!";
	
	/**
	 * a.处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常，详情继续往下看代码
	 * @param e
	 * @return
	 */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public String BindExceptionHandler(BindException e) {
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
        ResponseData<String> body = new ResponseData<String>();
		body.init(ResponseCode.FAIL_FLAG, message);
        return body.toResponse();
    }

    /**
     * a.处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public String ConstraintViolationExceptionHandler(ConstraintViolationException e) {
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
        ResponseData<String> body = new ResponseData<String>();
		body.init(ResponseCode.FAIL_FLAG, message);
        return body.toResponse();
    }

    /**
     * a请求参数格式错误@RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
        ResponseData<String> body = new ResponseData<String>();
		body.init(ResponseCode.FAIL_FLAG, message);
        return body.toResponse();
    }
    
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public String RuntimeExceptionHandler(RuntimeException e, HttpServletRequest request) {
    	ResponseData<String> body = new ResponseData<String>();
		body.init(ResponseCode.FAIL_FLAG, RUNTIME_EXP_MSG);
		logger.error("{}@{}, {}",request.getRequestURL(), request.getMethod(), RUNTIME_EXP_MSG, e);
        return body.toResponse();
    }
    
    @ExceptionHandler(SQLException.class)
    @ResponseBody
    public String SQLExceptionHandler(SQLException e, HttpServletRequest request) {
    	ResponseData<String> body = new ResponseData<String>();
		body.init(ResponseCode.FAIL_FLAG, SQL_EXP_MSG);
		logger.error("{}@{}, {}",request.getRequestURL(), request.getMethod(), SQL_EXP_MSG, e);
        return body.toResponse();
    }
    
    @ExceptionHandler(IOException.class)
    @ResponseBody
    public String IOExceptionHandler(IOException e, HttpServletRequest request) {
    	ResponseData<String> body = new ResponseData<String>();
		body.init(ResponseCode.FAIL_FLAG, IO_EXP_MSG);
		logger.error("{}@{}, {}",request.getRequestURL(), request.getMethod(), IO_EXP_MSG, e);
        return body.toResponse();
    }
}